home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / Libraries / C Internet Config / IC Read Only ƒ / IC Generic Override.c < prev    next >
Encoding:
Text File  |  1995-11-17  |  12.6 KB  |  405 lines  |  [TEXT/SPM ]

  1. h Toolbox very closely and test your component thoroughly.
  2.     You'll definitely want some tools off of develop 15, including
  3.     Komponent Killer, Reinstaller II and the "thing" dcmd.
  4.  
  5.     This code is probably of adequate quality for most uses, but if
  6.     you are using it to implement a commercial-quality system, you
  7.     may want to rewrite it from the ground up.
  8.  
  9.     Quinn "The Eskimo!"
  10.  
  11.     with vast plagarism from...
  12.  
  13.     Eric Kidd
  14.     eric.kidd@dartmouth.edu
  15.  
  16.     Thanks for all the work Eric!
  17.  
  18. */
  19.  
  20. #include <Components.h>
  21. #include <Folders.h>
  22.  
  23. #if USESROUTINEDESCRIPTORS
  24. #include <stdlib.h>
  25. #endif
  26.  
  27. #include "IC Keys.h"
  28. #include "IC Component Selectors.h"
  29. #include "IC Component API.h"
  30.  
  31. #include "IC Generic Override.h"
  32. #include "IC Specific Override.h"
  33.  
  34. // #include "IC Component Utils.h"
  35.  
  36. /*
  37.     ICGOFixCloneRefCon
  38.  
  39.     See Inside Macintosh: More Macintosh Toolbox p. 6-35 for
  40.     an overview of this silliness. It seems that when your globally-
  41.     registered component is opened by an application, the system
  42.     pulls a fast one under "certain circumstances" (not enough memory
  43.     in the system heap) and "clones" a locally-registered version
  44.     of your component, frying your RefCon in process.
  45.  
  46.     What we need to do is determine if this is the case, and if so,
  47.     recover the RefCon by locating the original copy of the component.
  48.  
  49.     The Officially Sactioned Way to do this is a bit of a hack. Global
  50.     components have an A5 world of zero when they are opened, but local
  51.     ones have it pre-set to the parent application's value. If your
  52.     supposedly global component detects that it has a pre-set A5 world,
  53.     then it's been cloned.
  54.  
  55.     To find the original copy of the component (which has the RefCon we
  56.     need), we need to find another component that looks exactly like us,
  57.     with the exception of a different component identifier. Unless we've
  58.     been registered globally multiple times under the same name, this
  59.     should work. FindNextComponent will do the job here.
  60.  
  61.     The "practical upshot" of this:
  62.         1) Only call this routine when handling open messages
  63.         2) Call it before setting your instance's A5 world
  64.         3) Only call it if you should have been global
  65.         4) It won't work if you've been registered multiple times
  66.             under the same name.
  67.         5) Don't use the same manufacturer code for different
  68.             components with the same type/subtype
  69.         6) It may not work at all. I'm a college student, dammit, not a
  70.             programming guru.
  71.  
  72.     Eric Kidd
  73.     eric.kidd@dartmouth.edu
  74.     16 Dec 94
  75. */
  76. pascal ComponentResult ICGOFixCloneRefCon(ComponentInstance self){
  77.     OSErr err=noErr;
  78.     ComponentDescription cd;
  79.     Component current;
  80.     
  81.     if ((GetComponentRefcon((Component)self)==0)&&(GetComponentInstanceA5(self)!=0)){
  82.         // if this component has not been opened & setup and we've been cloned
  83.         
  84.         // get enough info about ourself to recognize the original
  85.         GetComponentInfo((Component)self,&cd,0,0,0);
  86.         cd.componentFlagsMask=0L; // these shouldn't be relevant
  87.         
  88.         current=(Component)0;
  89.         
  90.         do {
  91.             // loop until we find someone other than ourself
  92.             current=FindNextComponent(current,&cd);
  93.             
  94.             if (current==(Component)0){
  95.                 // We didn't find any original--this happens often.
  96.                 // If we've been captured, we can't find the original copy.
  97.                 // Best thing to do is return an error.
  98.                 return paramErr;
  99.             }
  100.         } while (current!=(Component)self);
  101.         
  102.         if (current!=(Component)0)
  103.             SetComponentRefcon((Component)self,GetComponentRefcon(current));
  104.         
  105.         err=noErr;
  106.     }
  107.     
  108.     return err;
  109. }
  110.  
  111. /*
  112.     If the shared globals have not yet been allocated, we'll try to set them up and return them.
  113. */
  114. pascal ComponentResult ICGOGetSharedGlobals(GlobalsHandle globals){
  115.     ComponentResult err;
  116.     SharedGlobalsPtr shared;
  117.     
  118.     shared=(SharedGlobalsPtr)GetComponentRefcon((Component)(*globals)->self);
  119.     (*globals)->shared=shared;
  120.     
  121.     if (shared==(SharedGlobalsPtr)0){
  122.         shared=(SharedGlobalsPtr)NewPtrSysClear(sizeof(SharedGlobals));
  123.         err=MemError();
  124.         (*globals)->shared=(SharedGlobalsPtr)0;
  125.         
  126.         if (err!=noErr)
  127.             return err;
  128.         
  129.         (*globals)->shared=shared;
  130.         
  131.         // init our part of the shared globals
  132.         shared->delegate=0;
  133.         
  134.         // and remember the shared globals in our refcon
  135.         
  136.         SetComponentRefcon((Component)(*globals)->self,(long)shared);
  137.         
  138.         // Since our shared globals get set up only once at registration time,
  139.         // here's the perfect place to move ourselves to the default position in the component list
  140.         
  141.         err=SetDefaultComponent((Component)(*globals)->self,defaultComponentIdentical+defaultComponentAnyFlagsAnyManufacturer);
  142.         
  143.         if (err==noErr)
  144.             ICSOInitShared(globals);
  145.     }
  146.     
  147.     return err;
  148. }
  149.  
  150. // Component Manager Routines
  151.  
  152. /*
  153.     I'd love to allocate shared globals here, but certain versions of the Component Manager
  154.     don't call ICGORegister.  Additionally, calls to ICGOOpen and ICGOClose bracket the call if it
  155.     does get made.  Go Figure.
  156.     
  157.     We actually return a boolean value, false if we should be registered and true if we shouldn't.
  158. */
  159. pascal ComponentResult ICGORegister(GlobalsHandle globals){
  160.     
  161.     return (ComponentResult)false;
  162. }
  163.  
  164. /*
  165.     Eric's comment:
  166.         Does this break if we've been cloned? Does the clone get unregistered seperately and double dispose? Hmm.
  167.     FIIK )-:
  168. */
  169. pascal ComponentResult ICGOUnregister(GlobalsHandle globals){
  170.     ComponentResult result=-1,result2;
  171.     
  172.     if ((*globals)->shared!=(SharedGlobalsPtr)0){
  173.         // give the specifics opportunity to clean up its shared globals
  174.         
  175.         result=ICSOCleanShared(globals);
  176.         
  177.         // clean up our part of the shared globals
  178.         result2=UncaptureComponent((*globals)->shared->delegate);
  179.         
  180.         if (result==noErr)
  181.             result=result2;
  182.         
  183.         // dispose of the shared globals and set our refcon back to zero
  184.         
  185.         DisposePtr((Ptr)(*globals)->shared);
  186.         SetComponentRefcon((Component)(*globals)->self,0L);
  187.     }
  188.     
  189.     return result;
  190. }
  191.  
  192. /*
  193.     Handle the Component Manager CanDo request.
  194. */
  195. pascal ComponentResult ICGOCanDo(GlobalsHandle globals,short selector){
  196.     ComponentResult result;
  197.     
  198.     switch (selector){
  199.         case kComponentUnregisterSelect:
  200.         case kComponentOpenSelect:
  201.             result=(ComponentResult)1;
  202.             break;
  203.         default:
  204.             result=ICSOCanDo(globals,selector);
  205.             
  206.             if (result==delegateThisCallErr)
  207.                 result=ComponentFunctionImplemented((*globals)->delegate,selector);
  208.             else
  209.                 result++;
  210.             break;
  211.     }
  212.     
  213.     return result;
  214. }
  215.  
  216. pascal Component ICGOFindDelegate(Component after){
  217.     ComponentDescription cd;
  218.     ComponentDescription found_cd;
  219.     Component current;
  220.     Boolean found=false;
  221.     
  222.     cd.componentType=internetConfigurationComponentType;
  223.     cd.componentSubType=internetConfigurationComponentSubType;
  224.     cd.componentManufacturer=(OSType)0;
  225.     cd.componentFlags=0L;
  226.     cd.componentFlagsMask=0L;
  227.     
  228.     current=after;
  229.     
  230.     do {
  231.         current=FindNextComponent(current,&cd);
  232.         
  233.         if (current!=(Component)0){
  234.             if (GetComponentInfo(current,&found_cd,0,0,0)==noErr){
  235.                 found=(found_cd.componentManufacturer!=kOurComponentManufacturer);
  236.             }
  237.         }
  238.     } while ((!found)&&(current!=(Component)0));
  239.     
  240.     if (current==(Component)0){
  241.         // DebugStr("\pICGOFindDelegate failed to find one.");
  242.     }
  243.     
  244.     return current;
  245. }
  246.  
  247. /*
  248.     ICGOOpen
  249.     
  250.     This function has been substantially recrafted from the original.  Cloning
  251.     is now handled correctly (see the description of ICGOFixCloneRefCon and error
  252.     handling has been made more graceful by the addition of a dedicated control
  253.     structure.  A memory leak has been closed and OpenComponent can no longer
  254.     be called on a NULL component instance.
  255.     
  256.     If you're using the pascal version, you'll want to carefully examine the differences.
  257. */
  258. pascal ComponentResult ICGOOpen(GlobalsHandle globals,ComponentInstance self){
  259.     ComponentResult err;
  260.     Component cap,toCapture;
  261.     
  262.     globals=(GlobalsHandle)0;
  263.     err=ICGOFixCloneRefCon(self);
  264.     
  265.     if (err==noErr){
  266.         globals=(GlobalsHandle)NewHandleClear(sizeof(GlobalsRecord));
  267.         err=MemError();
  268.     }
  269.     
  270.     if (err==noErr){
  271.         HLock((Handle)globals);
  272.         (*globals)->self=self;
  273.         SetComponentInstanceStorage(self,(Handle)globals);
  274.         err=ICGOGetSharedGlobals(globals);
  275.     }
  276.     
  277.     if (err==noErr){
  278.         // if we haven't yet done so, find and capture the topmost IC component.  We'll
  279.         // save the special component identifier which will permit us to open it.
  280.         
  281.         if ((*globals)->shared->delegate==0){
  282.             toCapture=ICGOFindDelegate((Component)self);
  283.             
  284.             if (toCapture==(Component)0)
  285.                 err=icNothingToOverrideErr;
  286.             else
  287.                 (*globals)->shared->delegate=CaptureComponent(toCapture,(Component)self);
  288.         }
  289.         
  290.         if (err==noErr){
  291.             (*globals)->delegate=OpenComponent((*globals)->shared->delegate);
  292.             err=ComponentSetTarget(self,self);
  293.         }
  294.         if (err==noErr)
  295.             err=ICSOInitGlobals(globals);
  296.     }
  297.     
  298.     if (globals!=(GlobalsHandle)0)
  299.         HUnlock((Handle)globals);
  300.     
  301.     if (err!=noErr){
  302.         if (globals!=(GlobalsHandle)0){
  303.             DisposeHandle((Handle)globals);
  304.             SetComponentInstanceStorage(self,(Handle)0);
  305.         }
  306.     }
  307.     
  308.     return err;
  309. }
  310.  
  311. // handle the close request
  312. pascal ComponentResult ICGOClose(GlobalsHandle globals,ComponentInstance self){
  313.     if (globals!=(GlobalsHandle)0){
  314.         ICSOCleanGlobals(globals);
  315.         
  316.         if ((*globals)->delegate!=0)
  317.             CloseComponent((*globals)->delegate);
  318.         
  319.         DisposeHandle((Handle)globals);
  320.     }
  321.     
  322.     return noErr;
  323. }
  324.  
  325. // handle the target request
  326. pascal ComponentResult ICGOTarget(GlobalsHandle globals,ComponentInstance new_target){
  327.     ComponentResult err=noErr;
  328.     
  329.     (*globals)->target=new_target;
  330.     
  331.     if ((*globals)->delegate!=0)
  332.         err=ComponentSetTarget((*globals)->delegate,new_target);
  333.     
  334.     return err;
  335. }
  336.  
  337. // Internet Configuration specific routines
  338.  
  339. pascal ComponentResult main(ComponentParameters* params,Handle storage){
  340.     SignedByte s;
  341.     ComponentFunctionUPP proc;
  342.     ComponentResult res;
  343.     
  344. #if USESROUTINEDESCRIPTORS
  345.     __rsrcinit();
  346. #endif
  347.     
  348.     proc=(ComponentFunctionUPP)0;
  349.     
  350.     // DebugStr(SelectorToStr(params->what));
  351.     
  352.     switch (params->what){
  353.         // Component Manager Stuff
  354.         
  355.         case kComponentVersionSelect:
  356.             res=internetConfigurationComponentInterfaceVersion;
  357.             break;
  358.         case kComponentCanDoSelect:
  359.             proc=BuildNewProc(ICGOCanDo,uppICGOShortProcInfo);
  360.             break;
  361.         case kComponentOpenSelect:
  362.             proc=BuildNewProc(ICGOOpen,uppICGOInstanceProcInfo);
  363.             break;
  364.         case kComponentCloseSelect:
  365.             proc=BuildNewProc(ICGOClose,uppICGOInstanceProcInfo);
  366.             break;
  367.         case kComponentTargetSelect:
  368.             proc=BuildNewProc(ICGOTarget,uppICGOInstanceProcInfo);
  369.             break;
  370.         case kComponentRegisterSelect:
  371.             proc=BuildNewProc(ICGORegister,uppICGOGlobalsProcInfo);
  372.             break;
  373.         case kComponentUnregisterSelect:
  374.             proc=BuildNewProc(ICGOUnregister,uppICGOGlobalsProcInfo);
  375.             break;
  376.         
  377.         // this component type stuff
  378.         default:
  379.             proc=ICSOWhatToOverride((GlobalsHandle)storage,params->what);
  380.             break;
  381.     }
  382.     
  383.     if (storage!=(Handle)0){
  384.         s=HGetState(storage);
  385.         HLock(storage);
  386.     }
  387.     
  388.     res=delegateThisCallErr;
  389.     
  390.     if (proc!=(ComponentFunctionUPP)0){
  391.         res=CallComponentFunctionWithStorage(storage,params,proc);
  392.         DisposeRoutineDescriptor((UniversalProcPtr)proc);
  393.     }
  394.     
  395.     if ((storage!=(Handle)0)&&(params->what!=kComponentCloseSelect)){
  396.         HSetState(storage,s);
  397.     }
  398.     
  399. #if USESROUTINEDESCRIPTORS
  400.     __rsrcterm();
  401. #endif
  402.  
  403.     return res;
  404. }
  405.